package com.fanrui.code.thread;

import java.util.concurrent.TimeUnit;

import com.fanrui.code.thread.MainLoopPlus.StrongRunnable;

/**
 * 
 * 用来放在{@link MainLoopPlus}中，实现周期性的执行每帧逻辑
 * 
 *
 */
public abstract class FrameTask extends StrongRunnable implements Cloneable {

	private boolean fixedRateOrFixedDelay = true; // true:即FixedRate以固定时间间隔启动（执行）；false:即FixedDelay执行后间隔时间固定

	private long initialDelay;
	private long delay;
	private TimeUnit unit;

	/**
	 * 
	 * @param fixedRateOrFixedDelay
	 *            true:即FixedRate以固定时间间隔启动（执行）；false:即FixedDelay执行后间隔时间固定
	 * @param initialDelay
	 *            延迟多久开始第一次执行
	 * @param delay
	 *            执行间隔时间
	 * @param unit
	 *            前面两个参数对应的时间单位
	 */
	public FrameTask(boolean fixedRateOrFixedDelay, long initialDelay, long delay, TimeUnit unit) {
		super();
		this.fixedRateOrFixedDelay = fixedRateOrFixedDelay;
		this.initialDelay = initialDelay;
		this.delay = delay;
		this.unit = unit;
	}

	public boolean isFixedRateOrFixedDelay() {
		return fixedRateOrFixedDelay;
	}

	public long getInitialDelay() {
		return initialDelay;
	}

	public long getDelay() {
		return delay;
	}

	public TimeUnit getUnit() {
		return unit;
	}

	private long lastEndTime; // 上一次执行完毕时刻
	private int spendTime; // 上一次执行完毕时刻 － 上一次开始执行时刻（毫秒）

	@Override
	public final void strongRun() {
		long startTime = System.currentTimeMillis();
		if (lastEndTime == 0) {
			// 第一次执行
			lastEndTime = startTime;
		}
		int waitTime = (int) (startTime - lastEndTime);

		try {
			run(spendTime, waitTime, spendTime + waitTime);
		} finally {
			long endTime = System.currentTimeMillis();
			spendTime = (int) (endTime - startTime);
			lastEndTime = endTime;
		}
	}

	/**
	 * 
	 * 提供了距离上一次运行间隔时间细节的run方法。
	 * 
	 * @param spendTime
	 *            上一次执行花费了多少时间 ＝ 上一次执行完毕时刻 － 上一次开始执行时刻（毫秒）
	 * @param waitTime
	 *            上一次等待了多少时间 ＝ 本次开始执行时刻 － 上一次执行完毕时刻（毫秒）
	 * @param detlaTime
	 *            上一次运行到这一次开始运行之间的时间间隔 ＝ 本次开始执行时刻 － 上一次开始执行时刻（毫秒），即 spendTime＋waitTime
	 */
	protected abstract void run(int spendTime, int waitTime, int detlaTime);

	@Override
	public FrameTask clone() {
		try {
			return (FrameTask) super.clone();
		} catch (CloneNotSupportedException e) {
			throw new RuntimeException("克隆 FrameTask 出错了！", e);
		}
	}

}
